package com.example.wiki.service.impl;

import com.example.wiki.common.util.CopyUtil;
import com.example.wiki.common.vo.PageVo;
import com.example.wiki.entity.Content;
import com.example.wiki.entity.ContentExample;
import com.example.wiki.entity.Doc;
import com.example.wiki.entity.DocExample;
import com.example.wiki.exeception.BusinessException;
import com.example.wiki.exeception.BusinessExceptionCode;
import com.example.wiki.mapper.ContentMapper;
import com.example.wiki.mapper.DocMapper;
import com.example.wiki.req.DocQueryReq;
import com.example.wiki.req.DocSaveReq;
import com.example.wiki.service.DocService;
import com.example.wiki.util.RedisUtil;
import com.example.wiki.util.RequestContext;
import com.example.wiki.util.SnowFlake;
import com.example.wiki.vo.DocVo;
import com.example.wiki.websocket.WebSocketServer;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.util.StringUtil;
import org.slf4j.MDC;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.prefs.BackingStoreException;

@Service
public class DocServiceImpl implements DocService {

    @Autowired
    DocMapper docMapper;

    @Autowired
    ContentMapper contentMapper;

    @Autowired
    SnowFlake snowFlake;//使用雪花算法生成id

    @Autowired
    RedisUtil redisUtil;

    @Autowired
    WebSocketService webSocketService;

//    @Autowired
//    RocketMQTemplate rocketMQTemplate;

    @Override
    public PageVo<DocVo> list(DocQueryReq docQueryReq) {
        //组装sql
        DocExample docExample = new DocExample();
        docExample.setOrderByClause("sort asc");
        DocExample.Criteria criteria = docExample.createCriteria();

        //分页查询
        PageHelper.startPage(docQueryReq.getPage(), docQueryReq.getSize());
        List<Doc> list = docMapper.selectByExample(docExample);

        //处理数据后封装
        PageInfo<Doc> pageInfo = new PageInfo<>(list);
        List<DocVo> docVoList = CopyUtil.copyList(list, DocVo.class);
        PageVo<DocVo> pageVo = new PageVo<DocVo>();
        pageVo.setList(docVoList);
        pageVo.setTotal(pageInfo.getTotal());
        return pageVo;
    }

    @Override
    public List<DocVo> all(Long ebookId) {
        //组装sql
        DocExample docExample = new DocExample();

        //必顺有图书id参数才来查 ,不然就会查到  id = “”
        DocExample.Criteria criteria = docExample.createCriteria();
        criteria.andEbookIdEqualTo(ebookId);
        docExample.setOrderByClause("sort asc");
        List<Doc> docList = docMapper.selectByExample(docExample);

        List<DocVo> docVoList = CopyUtil.copyList(docList, DocVo.class);

        return docVoList;
    }

    @Override
    @Transactional //同一个类里A方法调用B方法，B方法中的事务不生效
    public void save(DocSaveReq docSaveReq) {
        Doc doc = CopyUtil.copy(docSaveReq, Doc.class);

        Content content = CopyUtil.copy(docSaveReq, Content.class);
        System.out.println(doc);
        if (doc.getId() == null || StringUtil.isEmpty(doc.getId().toString())) {
            doc.setId(snowFlake.nextId());
            doc.setViewCount(0);
            doc.setVoteCount(0);
            docMapper.insert(doc);

            content.setId(doc.getId());
            contentMapper.insert(content);
        } else {
            docMapper.updateByPrimaryKeySelective(doc);

            ContentExample contentExample = new ContentExample();
            ContentExample.Criteria criteria = contentExample.createCriteria();
            criteria.andIdEqualTo(doc.getId());
            // 如果要使用大字段要增加后缀如：BLOB
            int count = contentMapper.updateByExampleWithBLOBs(content, contentExample);
            if (count == 0) {
                // 如果无更新说明不存在,新增数据
                contentMapper.insert(content);
            }
        }
    }

    @Override
    public void remove(Long id) {
        if (id != null) {
            docMapper.deleteByPrimaryKey(id);
        }
    }

    @Override
    public void remove(List<String> asList) {

        DocExample docExample = new DocExample();
        DocExample.Criteria criteria = docExample.createCriteria();
        criteria.andIdIn(asList);
        docMapper.deleteByExample(docExample);
    }


    @Override
    public Content findContent(Long id) {
        if (id != null) {
            ContentExample contentExample = new ContentExample();
            ContentExample.Criteria criteria = contentExample.createCriteria();
            criteria.andIdEqualTo(id);

            List<Content> contents = contentMapper.selectByExampleWithBLOBs(contentExample);

            //文档阅读数加1
            docMapper.increaseViewCount(id);

            if (contents.size() > 0) {
                return contents.get(0);
            }
        }
        return null;
    }

    /**
     *文档点赞数数加1
     * @param id
     */
    @Override
    public void vote(Long id) {
        //获得线程变量  远程ip + doc.id 作为key 24小时不可重复
        String key = RequestContext.getRemoteAddr()+id;
        if(redisUtil.validateRepeat(key,3600*24)){
            //不存在 放入redis后新增数据
            docMapper.increaseVoteCount(id);
        }else {
            //redis存在说明已经点过赞
            throw new BusinessException(BusinessExceptionCode.VOTE_REPEAT);
        }

//       sendInfo(id);
        Doc doc = docMapper.selectByPrimaryKey(id);
        webSocketService.sendInfo("["+doc.getName()+"]被点赞了！", MDC.get("LOG_ID"));
          //业务主题与内容      // Async-4 使用rocketMQ推送消息
//        rocketMQTemplate.convertAndSend("Vote_Topic","["+doc.getName()+"]被点赞了！");
    }

    // Async-2
//    @Async //异步化失败 发现日志中日志流水号是一样的 说明是同一个线程
      //失败原因：异步化会生成代理类， 代理类下调用异步化方法无效，解决：新建代理类与其异步化方法后，其他类调用异步化方法
//    public void  sendInfo(Long id){
//        //点赞后推送消息
//        Doc doc = docMapper.selectByPrimaryKey(id);
//        webSocketServer.sendInfo("["+doc.getName()+"]被点赞了！");
//    }

    @Override
    public void updateEbookForDoc() {
        docMapper.updateEbookForDoc();
    }
}
